package com.ccepc.algmanage.scheduled;

import com.alibaba.fastjson.JSONObject;
import com.ccepc.algmanage.service.IdentificationRecordService;
import com.ccepc.algmanage.utils.CommonUtils;
import com.ccepc.algmanage.utils.HkUtils;
import com.ccepc.demo.api.constants.RecordConstants;
import com.ccepc.demo.api.dto.VideoRecordDto;
import com.ccepc.demo.api.entity.IdentificationRecord;
import com.ccepc.demo.api.entity.LinkedDevice;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class VideoRecordService {

    private ScheduledExecutorService executorService;

    private final static HkUtils hkUtils = new HkUtils("121.36.40.162:443", "22434065", "lKQa6FJYflYCCU59E6AB");

    @Resource
    private IdentificationRecordService identificationRecordService;

    @Resource
    private RedisTemplate<String, VideoRecordDto> redisTemplate;

    // 在类中定义一个 Map 用于存储 ScheduledFuture 对象，用来维护定时任务的执行
    private final Map<String, ScheduledFuture<?>> scheduledFutures = new HashMap<>();

    /**
     * 向联动设备发送请求并录制联动视频
     */
    @Async
    public void sendAndSaveRecord(List<LinkedDevice> linkedDevices, IdentificationRecord identificationRecord) {
        log.info("进入联动设备处理");
        // 给联动设备发请求
        linkedDevices.forEach(linkedDevice -> {
            String deviceNo = linkedDevice.getDeviceNo();
            // 将联动信息和原始时间以设备编号为key存储在Redis中保证记录的唯一性
            VideoRecordDto redisRecordDto = redisTemplate.opsForValue().get(RecordConstants.VIDEO_RECORD + deviceNo);
            if (redisRecordDto == null) {
                // 第一次创建时开启视频录制,并设置视频开始录制时间
                redisRecordDto = new VideoRecordDto();
                redisRecordDto.setIdentificationRecord(identificationRecord);
                redisRecordDto.setOriginTime(LocalDateTime.now());
                // 给联动设备发送请求
                sendRequest(linkedDevice);
                // 视频录制开始
                if (startRecording(deviceNo)) {
                    // 启动定时任务，每秒检查是否需要停止录制
                    executorService = Executors.newSingleThreadScheduledExecutor();
                    ScheduledFuture<?> future = executorService.scheduleAtFixedRate(() -> checkRecordingTime(deviceNo), 1, 1, TimeUnit.SECONDS);
                    scheduledFutures.put(deviceNo, future);
                }
            }
            // 每次请求都更新当前请求时间和缓存时间
            redisRecordDto.setLatestTime(LocalDateTime.now());
            redisTemplate.opsForValue().set(RecordConstants.VIDEO_RECORD + deviceNo, redisRecordDto, 15, TimeUnit.SECONDS);
        });
    }

    private void sendRequest(LinkedDevice linkedDevice) {
        // 实现发送请求给联动设备的逻辑
        log.info("发送请求给联动设备...");
    }

    private Boolean startRecording(String deviceNo) {
        // 实现开始录制的逻辑
        JSONObject startRes = CommonUtils.stringToJson(hkUtils.startCameraRecord(deviceNo));
        // 获取 taskID
        if ("0".equals(startRes.getString("code"))) {
            JSONObject data = startRes.getJSONObject("data");
            if (data.get("taskID") != null) {
                String taskID = data.getString("taskID");
                // 存储任务ID用于结束视频
                VideoRecordDto redisRecord = redisTemplate.opsForValue().get(RecordConstants.VIDEO_RECORD + deviceNo);
                if (redisRecord != null) {
                    redisRecord.setTaskId(taskID);
                    redisTemplate.opsForValue().set(RecordConstants.VIDEO_RECORD + deviceNo, redisRecord);

                    log.info("开始录制");
                    return true;
                } else {
                    hkUtils.stopCameraRecord(deviceNo, taskID);
                }
            } else {
                log.info("任务ID缺失");
            }
        } else {
            log.info("录制开启失败");
        }
        return false;
    }

    private void checkRecordingTime(String deviceNo) {
        // 查询数据库中摄像头编码相同的识别记录，并计算时间差
        VideoRecordDto redisRecordDto = redisTemplate.opsForValue().get(RecordConstants.VIDEO_RECORD + deviceNo);
        if (redisRecordDto != null) {
            String taskID = redisRecordDto.getTaskId();
            if (taskID != null) {
                LocalDateTime originTime = redisRecordDto.getOriginTime();
                LocalDateTime latestTime = redisRecordDto.getLatestTime();
                LocalDateTime currentTime = LocalDateTime.now();
                // 计算上一次请求到现在的时间间隔和第一次请求到现在的时间间隔
                Duration duration = Duration.between(latestTime, currentTime);
                Duration maxDuration = Duration.between(originTime, currentTime);
                // 如果距离上一次请求时间差超过5秒或者距离第一次请求时间差超过30秒，则停止录制
                if (duration.getSeconds() > 10 || maxDuration.getSeconds() > 30) {
                    stopRecording(deviceNo, taskID);
                }
            }
        }

    }

    private void stopRecording(String deviceNo, String taskID) {
        // 停止录制的逻辑
        VideoRecordDto redisRecordDto = redisTemplate.opsForValue().get(RecordConstants.VIDEO_RECORD + deviceNo);
        if (redisRecordDto != null) {
            JSONObject stopRes = CommonUtils.stringToJson(hkUtils.stopCameraRecord(deviceNo, taskID));
            // 获取录像url
            log.info("获取录像url");
            // 保存联动记录
            if ("0".equals(stopRes.getString("code"))) {
                log.info("结束录制");
                IdentificationRecord redisRecord = redisRecordDto.getIdentificationRecord();
                if (identificationRecordService.save(redisRecord)) {
                    log.info("联动记录保存成功！");
                    // 关闭定时任务，不会影响其他定时任务
                    ScheduledFuture<?> future = scheduledFutures.get(deviceNo);
                    if (future != null && !future.isCancelled()) {
                        future.cancel(true);
                    }
                } else {
                    log.error("联动记录保存失败！");
                }
            }
        }
    }

    @PreDestroy
    public void cleanup() {
        if (executorService != null && !executorService.isShutdown()) {
            executorService.shutdown();
        }
    }

}
